/**************************************************************************
File:        texttodll.cpp
Description: multiline edit widget which turns the text into a dll

Copyright:   (C) 2001 by ZJ Laczik
Email:       Zsolt.Laczik@eng.ox.ac.uk
****************************************************************************
Change log:
   begin      Fri Mar 16 2001
   15/2/2012	QT4 update
***************************************************************************/

#include "texttodll.h"

#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>

#include <QFile>
#include <QTextStream>
#include <QKeyEvent>
#include <QPalette>
#include <QProcess>

TTDLL_MultiLineEdit::TTDLL_MultiLineEdit(QWidget *parent) : QPlainTextEdit(parent)
{
    libname = "batchfn";

    mDirty = false;

    connect(this, SIGNAL(textChanged()), SLOT(setDirtyFlag()) );
    connect(this, SIGNAL(textChanged()), SLOT(resetBackGround()) );
}

TTDLL_MultiLineEdit::~TTDLL_MultiLineEdit()
{
    QString s;
    QString result;
    
    emit( StatusMsg( QString("Removing old DLL files (/tmp/zjlmm_%1*)") .arg(fn), true ) );
    QProcess rmoldfiles;
    rmoldfiles.setProcessChannelMode(QProcess::MergedChannels);
    rmoldfiles.start("/bin/rm", QStringList() << "-f" << QString("/tmp/zjlmm_%1*") .arg(fn));
    if (!rmoldfiles.waitForStarted(100)) {
        emit( StatusMsg( QString("TxtToDLL: Timeout - could not start rmoldfiles"), true ) );
        emit( StatusMsg( rmoldfiles.errorString(), true ));
        rmoldfiles.close();;
        setRedBackGround();
        return;
    };
    if (!rmoldfiles.waitForFinished(1000)) {
        emit( StatusMsg( QString("TxtToDLL: Timeout - taking too long to remove old files"), true ) );
        emit( StatusMsg( rmoldfiles.errorString(), true ));
        rmoldfiles.close();
        setRedBackGround();
        return;
    };
    result = rmoldfiles.readAll();
    if (result.length() != 0) {
        emit( StatusMsg( QString(result.left(256)), true ) );
        return;
    };
}

void  TTDLL_MultiLineEdit::focusOutEvent ( QFocusEvent * )
{
    if (mDirty) {
        MakeLib();
    };
}

void TTDLL_MultiLineEdit::keyPressEvent( QKeyEvent* e )
{
    if ((e->modifiers() == Qt::ShiftModifier) && (e->key() == Qt::Key_Return)) {
        if (mDirty) {
            MakeLib();
        };
    }
    else {
        QPlainTextEdit::keyPressEvent(e);
    };
    return;
}

void TTDLL_MultiLineEdit::clearDirtyFlag()
{
    mDirty = false;
}

void TTDLL_MultiLineEdit::setDirtyFlag()
{
    mDirty = true;
}

void TTDLL_MultiLineEdit::resetBackGround()
{
    QPalette p = palette();
    p.setColor(QPalette::Base, Qt::white);
    setPalette( p );

    repaint();
}

void TTDLL_MultiLineEdit::setRedBackGround()
{
    QPalette p = palette();
    p.setColor(QPalette::Base, QColor(0xff, 0xd0, 0xd0));
    setPalette( p );

    repaint();
}

void TTDLL_MultiLineEdit::setGreenBackGround()
{
    QPalette p = palette();
    p.setColor(QPalette::Base, QColor(0xdf, 0xff, 0xd0));
    setPalette( p );

    repaint();
}

void TTDLL_MultiLineEdit::MakeLib() {
    QString s;

    QString cfn;
    QString sofn;

    QProcess proc;
    QByteArray result;

    // remove previous version of lib.
    emit( StatusMsg( QString("Removing old DLL files (/tmp/zjlmm_%1*)") .arg(fn), true ) );
    QProcess rmoldfiles;
    rmoldfiles.setProcessChannelMode(QProcess::MergedChannels);
    rmoldfiles.start("/bin/rm", QStringList() << "-f" << QString("/tmp/zjlmm_%1*") .arg(fn));
    if (!rmoldfiles.waitForStarted(100)) {
        emit( StatusMsg( QString("TxtToDLL: Timeout - could not start rmoldfiles"), true ) );
        emit( StatusMsg( rmoldfiles.errorString(), true ));
        rmoldfiles.close();;
        setRedBackGround();
        return;
    };
    if (!rmoldfiles.waitForFinished(1000)) {
        emit( StatusMsg( QString("TxtToDLL: Timeout - taking too long to remove old files"), true ) );
        emit( StatusMsg( rmoldfiles.errorString(), true ));
        rmoldfiles.close();
        setRedBackGround();
        return;
    };
    result = rmoldfiles.readAll();
    if (result.length() != 0) {
        emit( StatusMsg( QString(result.left(256)), true ) );
        return;
    };
    
    // generate new unique name
    char st[256];
    sprintf(st, "%s_XXXXXX", libname.toUtf8().constData());
    mktemp( st );
    fn = st;

    cfn = QString("/tmp/zjlmm_") + fn + QString(".cc");
    sofn = QString("/tmp/zjlmm_") + fn + QString(".so");

    // save contents into a file
    s.sprintf("/tmp/zjlmm_%s.cc", fn.toUtf8().constData());
    QFile f( s );
    if ( !f.open( QIODevice::WriteOnly ) ) {
        emit( LibHasChanged( "<InvalidLibrary>" ) );
        setRedBackGround();
        return;
    };

    QTextStream t(&f);
    t << toPlainText();
    f.close();

    // compile DLL
    QProcess compiler;
    compiler.setProcessChannelMode(QProcess::MergedChannels);
    compiler.start("/usr/bin/g++", QStringList() << "-fPIC" << "-shared" << "-I/usr/include/qt4" << "-I." << cfn << "-o" << sofn << "-lm");
    if (!compiler.waitForStarted(100)) {
        emit( LibHasChanged( "<InvalidLibrary>" ) );
        emit( StatusMsg( QString("TxtToDLL: Timeout - could not start compiler"), true ) );
        emit( StatusMsg( compiler.errorString(), true ));
        compiler.close();;
        setRedBackGround();
        return;
    };
    if (!compiler.waitForFinished(1000)) {
        emit( LibHasChanged( "<InvalidLibrary>" ) );
        emit( StatusMsg( QString("TxtToDLL: Timeout - DLL generation taking too long"), true ) );
        emit( StatusMsg( compiler.errorString(), true ));
        compiler.close();
        setRedBackGround();
        return;
    };
    result = compiler.readAll();
    if (result.length() != 0) {
        emit( LibHasChanged( "<InvalidLibrary>" ) );
        emit( StatusMsg( QString("TxtToDLL: Compile errors"), true ) );
        emit( StatusMsg( QString(result.left(256)), true ) );
        setRedBackGround();
        return;
    };

    /*
    // set permissions on new library
    // commented out because default permissions seem to be OK
    QProcess setpermissions;
    setpermissions.setProcessChannelMode(QProcess::MergedChannels);
    setpermissions.start("/bin/chmod", QStringList() << "ug+x" << sofn);
    // return code / error checking should go in here (like above)
    */

    clearDirtyFlag();
    setGreenBackGround();

    s.sprintf( "TxtToDLL: Succesfully created /tmp/zjlmm_%s.so", fn.toUtf8().constData() );
    emit( StatusMsg( s, true ) );

    s.sprintf( "/tmp/zjlmm_%s.so", fn.toUtf8().constData() );
    emit( LibHasChanged( s.toUtf8().constData() ) );

    return;
}

void TTDLL_MultiLineEdit::slotCreateDefaultBatchfile()
{
    appendPlainText(
        QString(
            "void move_x_to(float x);\n"
            "void move_y_to(float y);\n"
            "void move_z_to(float z);\n"
            "void move_to(float x, float y, float z);\n"
            "void fire();\n"
            "void burst();\n"
            "bool stop();\n"
	    "// Use the above functions to create a batch routine,\n"
	    "// e.g. as shown below. N.B. There are no check performed\n"
	    "// when the batch routine is executed.\n"
	    "// If you make a mistake the program will probably crash.\n"
	    "// Save your work before you click the start batch button!\n\n"
            "void batch() {\n"
	    "  int i;\n"
	    "  for (i=0; i<10; i++) {\n"
	    "    move_x_to(i*10.0);\n"
	    "    if (stop()) break;\n"
	    "  }\n"
	    "  if (stop()) return;\n"
            "  move_to(0.0, 0.0, 0.0);\n"
            "}"
        )
    );
}
